package com.corx.network.core.manager;

import com.corx.network.core.listener.ReceivedMessageListener;
import com.corx.network.core.model.ReceivedMessage;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

/**
 * 网络组件接收信息监听器jar管理器
 *
 * @author gx
 * @version 2.0.0
 */
@Slf4j
public class ReceivedMessageListenerJarManager {

    /**
     * JAR ID -> Listener 实例
     */
    private final Map<String, ReceivedMessageListener<ReceivedMessage, ReceivedMessage>> listenerRegistry = new ConcurrentHashMap<>();

    /**
     * JAR ID -> 对应的类加载器，用于资源释放
     */
    private final Map<String, URLClassLoader> classLoaderMap = new ConcurrentHashMap<>();

    /**
     * 注册并加载 JAR，自动实例化实现了 TopicListener<ReceivedMessage> 的类
     */
    @SuppressWarnings("unchecked")
    public void registerJar(String jarId, File jarFile) throws Exception {
        if (!jarFile.exists() || !jarFile.getName().endsWith(".jar")) {
            throw new IllegalArgumentException("无效 JAR 文件：" + jarFile.getAbsolutePath());
        }

        // 如果存在旧的，则先卸载
        if (listenerRegistry.containsKey(jarId)) {
            unloadJar(jarId);
        }

        URLClassLoader classLoader = new URLClassLoader(
            new URL[]{jarFile.toURI().toURL()},
            this.getClass().getClassLoader()
        );
        classLoaderMap.put(jarId, classLoader);

        try (JarInputStream jarStream = new JarInputStream(new FileInputStream(jarFile))) {
            JarEntry entry;
            while ((entry = jarStream.getNextJarEntry()) != null) {
                String name = entry.getName();
                if (name.endsWith(".class")) {
                    String className = name.replace('/', '.').replace(".class", "");
                    try {
                        Class<?> clazz = classLoader.loadClass(className);

                        // 仅注册第一个匹配的监听器
                        if (ReceivedMessageListener.class.isAssignableFrom(clazz)) {
                            Object obj = clazz.getDeclaredConstructor().newInstance();
                            if (obj instanceof ReceivedMessageListener) {
                                listenerRegistry.put(jarId, (ReceivedMessageListener<ReceivedMessage, ReceivedMessage>) obj);
                                log.info("注册监听器类：{} -> {}", jarId, className);
                                break; // 一般一个 JAR 只注册一个主监听器
                            }
                        }
                    } catch (Throwable e) {
                        log.warn("类加载失败：{} - {}", className, e.getMessage());
                    }
                }
            }
        }
    }

    @SuppressWarnings("unchecked")
    public void registerJar(String jarId, URL jarUrl) throws Exception {
        // 如果存在旧的，则先卸载
        if (listenerRegistry.containsKey(jarId)) {
            unloadJar(jarId);
        }

        // 使用主项目的类加载器作为父加载器，避免类型冲突
        URLClassLoader classLoader = new URLClassLoader(new URL[]{jarUrl}, this.getClass().getClassLoader());
        classLoaderMap.put(jarId, classLoader);

        // 目标接口和泛型消息类
        Class<?> listenerInterface = ReceivedMessageListener.class;

        try (JarInputStream jarStream = new JarInputStream(jarUrl.openStream())) {
            JarEntry entry;
            while ((entry = jarStream.getNextJarEntry()) != null) {
                String name = entry.getName();
                if (name.endsWith(".class")) {
                    String className = name.replace('/', '.').replace(".class", "");

                    try {
                        Class<?> clazz = classLoader.loadClass(className);
                        // 是否实现了 TopicListener 接口（避免类加载器不一致的问题）
                        for (Class<?> iface : clazz.getInterfaces()) {
                            if (iface.getName().equals(listenerInterface.getName())) {
                                Object instance = clazz.getDeclaredConstructor().newInstance();

                                if (listenerInterface.isInstance(instance)) {
                                    // 仅注册第一个匹配的监听器
                                    listenerRegistry.put(jarId, (ReceivedMessageListener<ReceivedMessage, ReceivedMessage>) instance);
                                    log.info("注册监听器类：{} -> {}", jarId, className);
                                    return;
                                }
                            }
                        }
                    } catch (Throwable e) {
                        log.warn("加载类失败：{} - {}", className, e.toString());
                    }
                }
            }
        }

        log.warn("未在 JAR [{}] 中找到符合条件的 TopicListener 实现类", jarId);
    }


    /**
     * 获取某个 JAR 注册的监听器实例
     */
    public ReceivedMessageListener<ReceivedMessage, ReceivedMessage> getListener(String jarId) {
        ReceivedMessageListener<ReceivedMessage, ReceivedMessage> listener = listenerRegistry.get(jarId);
        return listener;
    }

    /**
     * 卸载 JAR，包括监听器和类加载器
     */
    public void unloadJar(String jarId) {
        // 1. 移除监听器实例
        ReceivedMessageListener<ReceivedMessage, ReceivedMessage> removed = listenerRegistry.remove(jarId);
        if (removed != null) {
//            try {
//                removed.onUnload(); // 如果实现了卸载钩子
//            } catch (Exception e) {
//                log.warn("卸载监听器时执行 onUnload 出错: {}", e.getMessage());
//            }
        }

        // 2. 关闭类加载器
        URLClassLoader classLoader = classLoaderMap.remove(jarId);
        if (classLoader != null) {
            try {
                classLoader.close();
            } catch (IOException e) {
                log.warn("关闭类加载器失败 [{}]: {}", jarId, e.getMessage());
            }
        }

        log.info("JAR [{}] 卸载完成", jarId);
    }

    /**
     * 当前已注册 JAR ID 列表
     */
    public Set<String> getRegisteredJarIds() {
        return listenerRegistry.keySet();
    }


    /**
     * 当前 JAR ID 是否已注册
     */
    public boolean getRegisteredJarIds(String jarId) {
        return listenerRegistry.containsKey(jarId);
    }

    /**
     * 释放所有资源：卸载所有 JAR，关闭类加载器，清空缓存。
     */
    public void shutdown() {
        log.info("[JarManager] 正在卸载所有已加载的 JAR...");
        for (String jarId : new HashSet<>(listenerRegistry.keySet())) {
            unloadJar(jarId);
        }
        log.info("[JarManager] 所有 JAR 资源已卸载完成");
    }

}
